Golang Project Template
Table of Contents
Golang Project Template #
tl;dr 🍴 the code and check it out: https://github.com/mikeblum/golang-project-template
Over the last year and change I’ve been writing lots of Golang to power a number of different tools and services. In other languages starting a new project can be as simple as rails new blog
in Rails or Spring Initializr in the JVM Spring Boot world.
Golang, on the other hand, takes a much more hands-off approach as opposed to the more prescriptive frameworks of other langs. As far as I can tell it’s not a cardinal sin to copypasta code from one repo to another in Golang vs building out micro repos or common libraries - in fact it seems encouraged.
Groundhog Day With A Gopher #
When starting a new Golang project, there are a number of libraries I’ve encountered via either blogs or, most often, by reading the code of other golang projects and taking bardic inspiration from their work.
As with any new project - no matter how small the scope - I find myself copy and pasting the same New
constructors and configs over and over again.
GOTO libraries 📚 #
At the moment I’ve coalesced around these awesome libraries - incidentally many of them made the awesome-go list!
pre-commit
: https://pre-commit.com/
A framework for managing and maintaining multi-language pre-commit hooks.
A poor man’s CI/CD these hooks can run locally as well as in ☁️ CI/CD. There are many different linters (watch out for abandoned ones!) to cover everything from Dockerfiles to catching credentials and things best not committed to version control.
golangci-lint
: https://golangci-lint.run/
Fast linters Runner for Go.
golangci-lint
has become an invaluable mentor and made me a much better Gopher. Interestingly the linters only recently became compatible with Go 1.18
via this Github issue
logrus
: https://github.com/sirupsen/logrus
Structured, pluggable logging for Go.
As of 1.19
Golang lacks an out-of-the-box structured logging library. Logrus has a stable API with flexible configuration that plays well locally as well as in the cloud with services like Datadog.
koanf
: https://github.com/knadh/koanf
Simple, lightweight, extensible, configuration management library for Go.
An idiomatic 12-factor library for loading both custom conf files as well as interpolating environment variables. I frequently pair koanf
with logrus
to configure logging for local dev (colored plain-text) vs cloud deployments (json format).
testify
: https://github.com/stretchr/testify
A toolkit with common assertions and mocks that plays nicely with the standard library.
While Golang’s stdlib import "testing"
and TestHelloWorld(t *testing.T)
are straight-forward I find the verbosity of sprinkling t
into every assertion to be cumbersome. testify
’s suite is an elegant API for setting up shared resources for package tests as well as tearing them down.
EDIT: After trying to do fuzzing and benchmarking, along with the unit and integration tests, I found myself fighting the suite
flow (esp the lack of hooks in vsCode). Rather the structs in the stdlib have been much easier to work with after adopting the convention of t.Run
: https://pkg.go.dev/testing
Resources #
Go By Example: an excellent resource for stdlib flows such as reading from a file, serializing http requests, or multi-threading with Go channels.
Golang Project Layout: there are a fair number of anti-patterns in this repo that don’t make sense. I’ve found this layout here to be much more ergonomic
Layout #
❌ top-level internal
directory as this messes with test coverage. Similarly a top level pkg directory is silly in most situations. A good use of internal
is for protobuf -generated code like this:
api/
user/
internal/
user.pb.go
user.go
user_test.go
proto/
user.proto
✅ domains for each top-level:
api/
user/
user.go
user_test.go
cmd/
app/
app.go
cli/
cli.go
db/
user/
user.go
user_test.go
web/
html/
js/
As a long time Java developer it took much restraint to stop tossing everything in a src
directory with com.bigcorp.proj
style Go modules. 🤦